import 'dart:math';

import 'package:flutter/material.dart';

const double itemHeight = 50;

class Item extends StatefulWidget {
  final OnMoveCallback onMove;
  final ItemModel itemModel;
  final int dismissDuration;
  final double itemWidth;

  const Item(this.itemWidth, this.itemModel, {Key key, this.onMove, this.dismissDuration = 100})
      : super(key: key);

  @override
  State<Item> createState() => _ItemState();
}

class _ItemState extends State<Item> with SingleTickerProviderStateMixin {
  double _itemWidth = 0;
  bool _visible = true;

  Animation<double> _dismissAnimation;
  AnimationController _dismissController;

  @override
  void initState() {
    _itemWidth = widget.itemWidth == 0 ? 100 : widget.itemWidth;
    _dismissController = AnimationController(vsync: this, duration: Duration(milliseconds: 1000));
    _dismissAnimation = Tween(begin: 1.0, end: 0.1).animate(_dismissController)
      ..addListener(() {
        setState(() {
          _itemWidth = _itemWidth * _dismissAnimation.value;
        });
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          // setState(() {
          //   _visible = false;
          // });
        }
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _moveAndDismiss();
      },
      child: Visibility(
        visible: _visible,
        maintainSize: true,
        maintainState: true,
        maintainAnimation: true,
        child: Container(
          width: _itemWidth,
          height: itemHeight,
          color: widget.itemModel.color,
        ),
      ),
    );
  }

  void _moveAndDismiss() {
    // setState(() {
    //   _visible = false;
    // });
    widget.onMove?.call(widget.itemModel);
    // _dismissController.forward();
  }

  @override
  void dispose() {
    _dismissController?.dispose();
    super.dispose();
  }
}

class MovingItem extends StatefulWidget {
  final int itemCount;
  final double itemWidth;
  final OnMoveComplete onMoveComplete;

  const MovingItem(this.itemWidth, this.itemCount, {Key key, this.onMoveComplete})
      : super(key: key);

  @override
  State<MovingItem> createState() => MovingItemState();
}

class MovingItemState extends State<MovingItem> with SingleTickerProviderStateMixin {
  double _initLeft = 0;
  double _initTop = 0;

  double _curLeft = 0;
  double _curTop = 0;
  ItemModel _curModel = ItemModel(Colors.transparent);

  bool _showMovingItem = false;

  double _deltaX = 0;
  double _deltaY = 0;

  Animation<double> _dismissAnimation;
  AnimationController _dismissController;

  @override
  void initState() {
    _dismissController = AnimationController(vsync: this, duration: Duration(milliseconds: 200));
    _dismissAnimation = Tween(begin: 0.0, end: 1.0).animate(_dismissController)
      ..addListener(() {
        setState(() {
          _curTop = _initTop + _deltaY * _dismissAnimation.value;
          _curLeft = _initLeft + _deltaX * _dismissAnimation.value;
        });
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          widget.onMoveComplete?.call(_curModel);
        }
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: _curLeft,
      top: _curTop,
      child: Offstage(
          offstage: !_showMovingItem,
          child: Container(
            width: widget.itemWidth,
            height: itemHeight,
            color: _curModel.color,
            // color: Colors.black,
          )),
    );
  }

  void startMove(ItemModel model, int startIndex) {
    _curModel = model;
    // start
    int num = startIndex + 1;
    int row = (num / 3).ceil();
    int column = (num % 3) == 0 ? 3 : num % 3;
    _initTop = (row - 1) * itemHeight;
    _initLeft = (column - 1) * widget.itemWidth;
    _curLeft = _initLeft;
    _curTop = _initTop;

    // des
    int desNum = widget.itemCount;
    int desRow = (desNum / 3).ceil();
    int desColumn = (desNum % 3) == 0 ? 3 : desNum % 3;
    double desTop = (desRow - 1) * itemHeight;
    double desLeft = (desColumn - 1) * widget.itemWidth;

    // delta
    _deltaX = desLeft - _initLeft;
    _deltaY = desTop - _initTop;
    setState(() {});

    _dismissController.forward(from: 0);
  }

  void show(bool show) {
    setState(() {
      _showMovingItem = show;
    });
  }

  @override
  void dispose() {
    _dismissController.dispose();
    super.dispose();
  }
}

typedef void OnMoveCallback(ItemModel model);
typedef void OnMoveComplete(ItemModel model);

Color randomColor() {
  return Color.fromARGB(
      255, Random().nextInt(256) + 0, Random().nextInt(256) + 0, Random().nextInt(256) + 0);
}

class ItemModel {
  final Color color;

  // final int index;

  // ItemModel(this.color, this.index);
  ItemModel(this.color);
}
